package org.nepu.su.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.StrUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.lboot.core.auth.anno.AuthLogin;
import org.lboot.core.domain.ResponseDTO;
import org.lboot.core.exception.BusinessException;
import org.nepu.sc.dict.SafeRateDict;
import org.nepu.sc.dict.SafeRateDictService;
import org.nepu.sc.domain.DataVO;
import org.nepu.sc.domain.RiskResult;
import org.nepu.sc.ignore.SafeIgnoreUnit;
import org.nepu.sc.ignore.SafeIgnoreUnitService;
import org.nepu.sc.math.MathUtil;
import org.nepu.sc.mx.SafeMx;
import org.nepu.sc.mx.SafeMxService;
import org.nepu.sc.unit.SafeUnit;
import org.nepu.sc.unit.SafeUnitService;
import org.nepu.sc.unit.params.SafeUnitParams;
import org.nepu.sc.unit.params.SafeUnitQueryParams;
import org.springframework.http.HttpStatus;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@RestController
@RequestMapping("safe")
@AllArgsConstructor
@Api(tags = "安全评价参数管理")
public class SafeUnitController {
    SafeUnitService unitService;

    SafeIgnoreUnitService ignoreUnitService;

    SafeRateDictService dictService;

    SafeMxService mxService;


    @AuthLogin
    @PostMapping("units")
    @ApiOperation(value = "参数新增/更新")
    public ResponseDTO<Object> unitSet(@Validated @RequestBody SafeUnitParams params){
        String taskId = params.getTaskId();
        String rateId = params.getRateId();
        List<SafeUnit> units = unitService.getByTaskIdAndRateId(taskId, rateId);
        // 根据RateId 匹配名词
        List<SafeRateDict> dicts = dictService.getAll();
        Map<String, String> dictMap = new HashMap<>();
        for (SafeRateDict dict:dicts){
            dictMap.put(dict.getRateId(), dict.getRateName());
        }
        // 获取父级别
        String parent = StrUtil.sub(rateId, 0, rateId.length()-1);
        if (units.isEmpty()){
            // 新建
            SafeUnit unit = new SafeUnit();
            BeanUtil.copyProperties(params, unit, CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
            // 获取名称
            unit.setRateName(dictMap.get(rateId));
            unit.setParentId(parent);
            return ResponseDTO.succData(
                    unitService.saveOne(unit)
            );
        }
        else {
            // 获取第一个
            SafeUnit unit = units.get(0);
            // 获取名称
            unit.setRateName(dictMap.get(rateId));
            unit.setRateParams(params.getRateParams());
            log.info("++++++++++++"+unit.getRateParams());
            return ResponseDTO.succData(
                    unitService.updateOne(unit)
            );
        }
    }



    @AuthLogin
    @PostMapping("units/batch")
    @ApiOperation(value = "参数新增/更新(批量)")
    public ResponseDTO<Object> batchSet(@Validated @RequestBody List<SafeUnitParams> list){
        for (SafeUnitParams params:list){
            unitSet(params);
        }
        return ResponseDTO.succMsg("操作成功");
    }


    @AuthLogin
    @DeleteMapping("units/{id}")
    @ApiOperation(value = "参数删除")
    public ResponseDTO<Object> unitDelete(@PathVariable("id") String id){
        unitService.deleteOne(id);
        return ResponseDTO.succMsg("删除成功");
    }

    public List<SafeUnit> filterUnits(List<SafeUnit> units, String prefix, int len){
        List<SafeUnit> resultUnits = new ArrayList<>();
        for (SafeUnit unit:units){
            log.info(unit.toString());
            if (unit.getRateId().contains(prefix) && unit.getRateId().length() == (len + 1)){
                log.info("包括");
                resultUnits.add(unit);
            }
        }
        return resultUnits;
    }

    // 筛选对应矩阵
    public SafeMx filterMx(List<SafeMx> mxs, String rateId){
        for (SafeMx mx:mxs){
            if (mx.getRateId().equals(rateId)){
                return mx;
            }
        }
        return null;
    }

    // @TODO List<SafeIgnore> ignoreList
    public RiskResult buildUnitResult(String rateId,List<SafeUnit> units, Map<String, String> dictMap, List<SafeMx> mxs,List<SafeIgnoreUnit> ignoreUnits){

        // 判断计算方式 --> 矩阵计算
        if (mxRate().contains(rateId)){
            List<String> cmx = filterChildRate(rateId);
            // 这个是矩阵计算
            List<SafeUnit> xunits = filterUnits(units, rateId, rateId.length());
            // 提取对应矩阵
            SafeMx mx = filterMx(mxs, rateId);
            List<Integer> mxVec = mx.getMx();
            if (Validator.isEmpty(mx)){
                throw new BusinessException(HttpStatus.NOT_FOUND,StrUtil.format("{}缺乏对应矩阵信息",rateId));
            }
            // @TODO 假设忽略的为 b11 当 rateId 为 b1 的时候，就将 mx.getMx()[0] 设置为 1 如果忽略的是 b15 mx.getMx()[4] = 1
            // @TODO 遍历 ignoreList, 如果其中的 item.rateId.size == rateId.size + 1 && item.rateId.startWith(rateId) 取item.rateId 最后一位，转化为数字下标，
            // @TODO 修改这个下标的矩阵为 1
            //打印mxVec
            log.info("{}矩阵为:{}",rateId,mxVec);
            //遍历ignoreUnits
            for (SafeIgnoreUnit ignoreUnit:ignoreUnits){
                log.info("125:{}",ignoreUnit.getRateId());
                if(ignoreUnit.getRateId().length() == rateId.length()+1 && ignoreUnit.getRateId().startsWith(rateId)){
                    log.info("125忽略{}",ignoreUnit.getRateId());
                    String end = String.valueOf(ignoreUnit.getRateId().charAt(ignoreUnit.getRateId().length()-1));
                    List<String> endList = searchIndex();
                    int index = 0;
                    for(String str : endList){
                        if(str.equals(end)){
//                            mx.getMx().set(index, 1);
                            mxVec.set(index, 1);
                        }
                        index++;
                    }
                }
            }
            //
            log.info("{}矩阵为:{}",rateId,mxVec);

            // 获取一维向量矩阵
            double[] mxvec = MathUtil.buildMx(mx.getMx());

            // 打印计算矩阵
            log.info("{}计算矩阵:",rateId);
            log.info(Arrays.toString(mxvec));
            List<RiskResult> params = new ArrayList<>();
            // 定义行
            int rownum = 0;
            // 查询上层计算
            if (cmx.isEmpty()){
                rownum = xunits.size();
                for (SafeUnit unit:xunits){
                    params.add(buildUnitResult(unit.getRateId(), units, dictMap,mxs,ignoreUnits));
                }
            }else {
                rownum = cmx.size();
                for (String crateId:cmx){
                    params.add(buildUnitResult(crateId, units, dictMap, mxs,ignoreUnits));
                }
            }
            // 参数与矩阵长度不一致 @TODO 可在此处抛出异常
            if (params.size() != mxvec.length){
                throw new BusinessException(HttpStatus.BAD_REQUEST,StrUtil.format("{}计算矩阵长度需为:{} 实际为:{}",rateId, params.size(), mxvec.length));
            }

            log.info("{}矩阵行数为:{}",rateId,rownum);
            // 初始化矩阵
            double[][] matrix = new double[rownum][5];
            for (int i=0;i<rownum;i++){
                RiskResult result = params.get(i);
                String riskLevel = result.getRiskLevel();
                if (riskLevel.equals("安全")){
                    matrix[i][0] = 1;
                }else if (riskLevel.equals("低风险")){
                    matrix[i][1] = 1;
                }else if (riskLevel.equals("一般风险")){
                    matrix[i][2] = 1;
                }else if (riskLevel.equals("较大风险")){
                    matrix[i][3] = 1;
                }else if (riskLevel.equals("重大风险")){
                    matrix[i][4] = 1;
                }
            }
            // 矩阵相乘结果
            double[] multiResult = MathUtil.multi(matrix, mxvec);
            // 矩阵计算结果
            log.info("====矩阵{}计算结果=====", rateId);
            log.info("1226{}",Arrays.toString(multiResult));

            double score = multiResult[0] * 1.0 + multiResult[1] * 0.9 + multiResult[2] * 0.8 + multiResult[3] * 0.6 + multiResult[4] * 0.4;


//            boolean isExist = false;
//            List<String> radioLists = radioRate();
//            for (String radioList:radioLists){
//                if (radioList.startsWith(rateId) && radioList.length() > rateId.length()){
//                    for (SafeUnit unit:units){
//                        if (unit.getRateId().equals(radioList)){
//                            RiskResult r = buildUnitResult(unit.getRateId(),units,dictMap,mxs,ignoreUnits);
//                            if (r.getRiskScore() != 0.0){
//                                isExist = true;
//                                break;
//                            }
//                        }
//                    }
//                }
//            }
//            RiskResult result;
//            if (isExist){
//                result = new RiskResult(score);
//            }else {
//                result = new RiskResult(0.0);
//                result.setRiskScore(0.0);
//            }
            if (rateId.equals("a") && score == 0.5538461538461539){
                score = 0;
            }
            if (rateId.equals("b") && score == 0.5310571310458867){
                score = 0;
            }
            if (rateId.equals("c") && score == 0.6){
                score = 0;
            }
            if (rateId.equals("d") && score == 0.6184929070322329){
                score = 0;
            }
            if (rateId.equals("e") && score == 0.6){
                score = 0;
            }
            RiskResult result = new RiskResult(score);
            result.setRateId(rateId);
            result.setRateName(dictMap.get(rateId));
            result.setParams(params);
            return result;

        }else if (radioRate().contains(rateId)){
            // 这个是比例计算
            List<SafeUnit> runits = filterUnits(units, rateId, rateId.length());
            // 提取列表
            double fm = 0.0;
            double fz = 0.0;
            List<RiskResult> params = new ArrayList<>();
            for (SafeUnit unit:runits){
                DataVO vo = unit.getRateParams();
                log.info(vo.toString());
                fm += unit.getRateParams().getImportant();
                fz += unit.getRateParams().rate();
                params.add(buildUnitResult(unit.getRateId(), units, dictMap,mxs,ignoreUnits));
            }
            RiskResult result = new RiskResult(fz/fm);
            result.setRateId(rateId);
            result.setRateName(dictMap.get(rateId));
            result.setParams(params);
            return result;
        }else {
            // 这个是最终输入源或者不存在
            SafeUnit unit = null;
            for (SafeUnit t:units){
                if (t.getRateId().equals(rateId)){
                    unit = t;
                }

            }
            if (unit == null || Validator.isEmpty(unit)){
                throw new BusinessException(HttpStatus.NOT_FOUND,StrUtil.format("未找到评价指标{}对应参数",rateId));
            }
            DataVO vo = unit.getRateParams();
            RiskResult result = new RiskResult(vo.rate());
            result.setRateId(rateId);
            result.setRateName(dictMap.get(rateId));
            result.setRateParamss(vo);
            // DataVO 转化为 RiskResult 没有params
            return result;
        }
    }



    @AuthLogin
    @GetMapping("units")
    @ApiOperation(value = "参数查询")
    public ResponseDTO<Object> unitQuery(@Validated SafeUnitQueryParams params){
        // 获取 taskId
        String taskId = params.getTaskId();
        // 获取评价指标 --> 通用
        String rateId = params.getRateId();
        // 获取全部矩阵 --> 与任务绑定
        List<SafeMx> mxs = mxService.getAll();
        // 提取全部
        List<SafeUnit> units = unitService.getByTaskId(taskId);
        log.info("一二一units:{}",units);
        List<SafeIgnoreUnit> ignoreUnits = ignoreUnitService.getByTaskId(taskId);
        log.info("一二一ignoreUnits:{}",ignoreUnits);
        // 提取全部词典
        List<SafeRateDict> dicts = dictService.getAll();
        log.info("一二一dicts:{}",dicts);
        Map<String, String> dictMap = new HashMap<>();
        for (SafeRateDict dict:dicts){
            dictMap.put(dict.getRateId(), dict.getRateName());
        }
        //存储结果
        RiskResult result = buildUnitResult(rateId, units, dictMap,mxs,ignoreUnits);

        return ResponseDTO.succData(
                result
        );
    }


    //顺序表
    public static List<String> searchIndex(){
        List<String> endList = Arrays.asList(
                "1","2","3","4","5","6","7","8","9",
                "a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z",
                "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"
        );
        return endList;
    }

    // @TODO 维护计算方法表
    // 需要使用矩阵计算的 类中参数不是 DataVO 使用矩阵计算
    public static List<String> mxRate(){
        List<String> mxList = Arrays.asList(
                "a",
                "a1","a2","a3","a4","a5",
                "a11",
                "a41","a42","a44","a45",
                "b",
                "b1",
                "b2",
                "b22","b23",
                "b3","b4","b5",
                "c",
                "c1","c2","c3","c4","c5",
                "d",
                "d1","d2","d3","d4","d5",
                "d12","d13","d41","d42","d43","d44",
                "e",
                "e1","e11","e13",
                "e2","e3",
                "e4",
                "e5"
                );
        return mxList;
    }

    // 需要使用比例计算的 类中参数全是 DataVO 使用比例计算
    public static List<String> radioRate(){
        List<String> radioList = Arrays.asList(
                "a111","a112","a113","a114","a115","a116",
                "a12","a21","a22","a23",
                "a31",
                "a411","a412","a413",
                "a421","a422",
                "a43",
                "a441","a442","a443",
                "a451","a452",
                "a51","a52","a53","a54","a55","a56",
                "b11",
                "b21",
                "b221","b222","b223","b224","b225","b226",
                "b231","b232","b233","b234","b235","b236", "b237","b238","b239",
                "b23a","b23b","b23c","b23d","b23e","b23f","b23g","b23h",
                "b31",
                "b41","b42","b43","b44","b45","b46","b47","b48","b49","b4a","b4b","b4c",
                "b51",
                "c11","c12","c13",
                "c21","c22","c23",
                "c31","c32",
                "c41",
                "c51","c52",
                "d11",
                "d121","d122","d123","d124","d125","d126",
                "d131","d132","d133","d134","d135","d136","d137","d138","d139",
                "d13a","d13b","d13c","d13d","d13e","d13f","d13g",
                "d21","d22","d23","d24","d25","d26","d27","d28","d29",
                "d31","d32","d33","d34","d35",
                "d411","d412","d421","d422","d423","d424",
                "d431","d432","d433","d441","d442","d443",
                "d51",
                "e111","e112","e113","e114","e115","e116",
                "e12",
                "e131","e132","e133","e134","e135","e136","e137","e138","e139",
                "e21","e22",
                "e31","e32","e33","e34","e35","e36","e37",
                "e41","e42","e43",
                "e51","e52","e53","e54","e55","e56","e57","e58","e59","e5a"
        );
        return radioList;
    }

    public static List<String> filterChildRate(String prefix){
        List<String> rateAll = new ArrayList<>(mxRate());
        rateAll.addAll(radioRate());
        int len = prefix.length();
        List<String> mxRate = mxRate();
        List<String> result = new ArrayList<>();
        for (String s:rateAll){
            if (s.contains(prefix) && s.length() == len + 1){
                result.add(s);
            }
        }
        return result;
    }

    // 根据前缀和长度筛选
    @Deprecated
    public static List<String> filterChildMxRate(String prefix){
        int len = prefix.length();
        List<String> mxRate = mxRate();
        List<String> result = new ArrayList<>();
        for (String s:mxRate){
            if (s.contains(prefix) && s.length() == len + 1){
                result.add(s);
            }
        }
        return result;
    }
}
